package GUI;

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.JComboBox;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.AbstractAction;
import java.awt.event.ActionEvent;
import javax.swing.Action;

import simulation.Cache;
import simulation.Simulator;
import simulation.Tomasulo;

import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import java.awt.Color;
import java.awt.Font;
import java.util.ArrayList;


public class MemoryHierarchy extends JFrame implements ItemListener,ActionListener{

	Simulator simulator = new Simulator();
	Tomasulo tomasulo;
	ArrayList<Cache> cachesList=new ArrayList<Cache>();
	private JPanel contentPane;
	private JTextField textFieldSICache1;
	private JTextField textFieldSCache2;
	private JTextField textFieldSCache3;
	private JTextField textFieldLCache1;
	private JTextField textFieldMCache1;
	private JTextField textFieldLCache2;
	private JTextField textFieldMCache2;
	private JTextField textFieldLCache3;
	private JTextField textFieldMCache3;
	private JButton btnNext;
	private JLabel lblWritePolicy;
	private JLabel lblMemoryCapacity;
	private JLabel lblAccessTime;
	private final Action action = new SwingAction();
	private JComboBox comboBoxWritePolicy;
	JLabel lblCache2;
	JLabel lblCache3;
	JLabel lblError;
	private JTextField textFieldMemoryAccessTime;
	JComboBox comboBoxCacheLevels;
	private JLabel lblAccess;
	private JTextField textFieldAccessTimeCache1;
	private JTextField textFieldAccessTimeCache2;
	private JTextField textFieldAccessTimeCache3;
	private JTextField textFieldSDCache1;
	private JLabel lblI;
	private JLabel lblD;
	private JComboBox comboBoxWritePolicy2;
	private JLabel label;
	private JLabel lblCache2WritePolicy;
	private JLabel lblCache3WritePolicy;
	private JComboBox comboBoxWritePolicy3;
	JComboBox comboBoxMemoryCapacity;
	String[] capacityList = new String[] {"32", "64", "128", "256", "512"};
	private int memoryAccessTime;
	private JLabel lblRequired;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					MemoryHierarchy frame = new MemoryHierarchy();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public MemoryHierarchy() {
		setResizable(false);
		setTitle("Memory Hierarchy");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 543, 480);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(null);
		
		JLabel lblCacheLevels = new JLabel("Cache Levels");
		lblCacheLevels.setHorizontalAlignment(SwingConstants.CENTER);
		lblCacheLevels.setBounds(10, 11, 76, 20);
		contentPane.add(lblCacheLevels);
		
		comboBoxCacheLevels = new JComboBox();
		comboBoxCacheLevels.setModel(new DefaultComboBoxModel(new String[] {"1", "2", "3"}));
		comboBoxCacheLevels.setSelectedIndex(0);
		comboBoxCacheLevels.setBounds(96, 11, 34, 20);
		comboBoxCacheLevels.addItemListener(this);
		contentPane.add(comboBoxCacheLevels);
		
		
		JLabel lblCache1 = new JLabel("Cache 1");
		lblCache1.setBounds(45, 42, 51, 14);
		contentPane.add(lblCache1);
		
		lblCache2 = new JLabel("");
		lblCache2.setBounds(116, 42, 51, 14);
		contentPane.add(lblCache2);
		
		lblCache3 = new JLabel("");
		lblCache3.setBounds(190, 42, 51, 14);
		contentPane.add(lblCache3);
		
		JLabel lblS = new JLabel("S");
		lblS.setToolTipText("cahe size");
		lblS.setHorizontalAlignment(SwingConstants.CENTER);
		lblS.setBounds(10, 77, 24, 14);
		contentPane.add(lblS);
		
		JLabel lblL = new JLabel("L");
		lblL.setToolTipText("cache line size");
		lblL.setHorizontalAlignment(SwingConstants.CENTER);
		lblL.setBounds(10, 120, 24, 14);
		contentPane.add(lblL);
		
		JLabel lblM = new JLabel("M");
		lblM.setToolTipText("Associativity");
		lblM.setHorizontalAlignment(SwingConstants.CENTER);
		lblM.setBounds(10, 160, 24, 14);
		contentPane.add(lblM);
		
		textFieldSICache1 = new JTextField();
		textFieldSICache1.setBorder(null);
		textFieldSICache1.setBounds(45, 67, 34, 14);
		contentPane.add(textFieldSICache1);
		textFieldSICache1.setColumns(10);
		
		textFieldSCache2 = new JTextField();
		textFieldSCache2.setVisible(false);
		textFieldSCache2.setEnabled(false);
		textFieldSCache2.setBorder(null);
		textFieldSCache2.setColumns(10);
		textFieldSCache2.setBounds(126, 74, 34, 20);
		contentPane.add(textFieldSCache2);
		
		textFieldSCache3 = new JTextField();
		textFieldSCache3.setVisible(false);
		textFieldSCache3.setBorder(null);
		textFieldSCache3.setEnabled(false);
		textFieldSCache3.setColumns(10);
		textFieldSCache3.setBounds(196, 74, 34, 20);
		contentPane.add(textFieldSCache3);
		
		textFieldLCache1 = new JTextField();
		textFieldLCache1.setBorder(null);
		textFieldLCache1.setColumns(10);
		textFieldLCache1.setBounds(45, 117, 34, 20);
		contentPane.add(textFieldLCache1);
		
		textFieldMCache1 = new JTextField();
		textFieldMCache1.setBorder(null);
		textFieldMCache1.setColumns(10);
		textFieldMCache1.setBounds(45, 157, 34, 20);
		contentPane.add(textFieldMCache1);
		
		textFieldLCache2 = new JTextField();
		textFieldLCache2.setEnabled(false);
		textFieldLCache2.setVisible(false);
		textFieldLCache2.setBorder(null);
		textFieldLCache2.setColumns(10);
		textFieldLCache2.setBounds(126, 117, 34, 20);
		contentPane.add(textFieldLCache2);
		
		textFieldMCache2 = new JTextField();
		textFieldMCache2.setEnabled(false);
		textFieldMCache2.setVisible(false);
		textFieldMCache2.setBorder(null);
		textFieldMCache2.setColumns(10);
		textFieldMCache2.setBounds(126, 157, 34, 20);
		contentPane.add(textFieldMCache2);
		
		textFieldLCache3 = new JTextField();
		textFieldLCache3.setVisible(false);
		textFieldLCache3.setEnabled(false);
		textFieldLCache3.setBorder(null);
		textFieldLCache3.setColumns(10);
		textFieldLCache3.setBounds(196, 117, 34, 20);
		contentPane.add(textFieldLCache3);
		
		textFieldMCache3 = new JTextField();
		textFieldMCache3.setVisible(false);
		textFieldMCache3.setEnabled(false);
		textFieldMCache3.setBorder(null);
		textFieldMCache3.setColumns(10);
		textFieldMCache3.setBounds(196, 157, 34, 20);
		contentPane.add(textFieldMCache3);
		
		btnNext = new JButton("Next");
		btnNext.addActionListener(this);
		btnNext.setAction(action);
		btnNext.setBounds(398, 373, 89, 23);
		contentPane.add(btnNext);
		
		lblWritePolicy = new JLabel("Write Policy");
		lblWritePolicy.setHorizontalAlignment(SwingConstants.CENTER);
		lblWritePolicy.setBounds(114, 242, 76, 20);
		contentPane.add(lblWritePolicy);
		
		lblMemoryCapacity = new JLabel("Capacity");
		lblMemoryCapacity.setHorizontalAlignment(SwingConstants.CENTER);
		lblMemoryCapacity.setBounds(387, 88, 67, 17);
		contentPane.add(lblMemoryCapacity);
		
		lblAccessTime = new JLabel("Memory Access Time");
		lblAccessTime.setHorizontalAlignment(SwingConstants.CENTER);
		lblAccessTime.setBounds(357, 166, 145, 17);
		contentPane.add(lblAccessTime);
		
		comboBoxWritePolicy = new JComboBox();
		comboBoxWritePolicy.setModel(new DefaultComboBoxModel(new String[] {"Writeback - Write alloacte", "Write-through - Write around"}));
		comboBoxWritePolicy.setBounds(69, 273, 208, 32);
		contentPane.add(comboBoxWritePolicy);
		
		textFieldMemoryAccessTime = new JTextField();
		textFieldMemoryAccessTime.setBounds(387, 194, 86, 20);
		contentPane.add(textFieldMemoryAccessTime);
		textFieldMemoryAccessTime.setColumns(10);
		
		lblError = new JLabel("Please choose applicable values");
		lblError.setVisible(false);
		lblError.setForeground(Color.RED);
		lblError.setBounds(342, 326, 190, 23);
		contentPane.add(lblError);
		
		comboBoxMemoryCapacity = new JComboBox();
		comboBoxMemoryCapacity.setModel(new DefaultComboBoxModel(capacityList));
		comboBoxMemoryCapacity.setBounds(387, 117, 83, 20);
		contentPane.add(comboBoxMemoryCapacity);
		
		lblAccess = new JLabel("Time");
		lblAccess.setToolTipText("Access time to the cache");
		lblAccess.setFont(new Font("Tahoma", Font.PLAIN, 11));
		lblAccess.setBounds(10, 197, 46, 14);
		contentPane.add(lblAccess);
		
		textFieldAccessTimeCache1 = new JTextField();
		textFieldAccessTimeCache1.setBorder(null);
		textFieldAccessTimeCache1.setColumns(10);
		textFieldAccessTimeCache1.setBounds(45, 196, 34, 20);
		contentPane.add(textFieldAccessTimeCache1);
		
		textFieldAccessTimeCache2 = new JTextField();
		textFieldAccessTimeCache2.setEnabled(false);
		textFieldAccessTimeCache2.setVisible(false);
		textFieldAccessTimeCache2.setBorder(null);
		textFieldAccessTimeCache2.setColumns(10);
		textFieldAccessTimeCache2.setBounds(126, 196, 34, 20);
		contentPane.add(textFieldAccessTimeCache2);
		
		textFieldAccessTimeCache3 = new JTextField();
		textFieldAccessTimeCache3.setBorder(null);
		textFieldAccessTimeCache3.setVisible(false);
		textFieldAccessTimeCache3.setEnabled(false);
		textFieldAccessTimeCache3.setColumns(10);
		textFieldAccessTimeCache3.setBounds(196, 196, 34, 20);
		contentPane.add(textFieldAccessTimeCache3);
		
		textFieldSDCache1 = new JTextField();
		textFieldSDCache1.setBorder(null);
		textFieldSDCache1.setColumns(10);
		textFieldSDCache1.setBounds(45, 89, 34, 14);
		contentPane.add(textFieldSDCache1);
		
		lblI = new JLabel("I");
		lblI.setHorizontalAlignment(SwingConstants.LEFT);
		lblI.setBounds(32, 67, 24, 14);
		contentPane.add(lblI);
		
		lblD = new JLabel("D");
		lblD.setHorizontalAlignment(SwingConstants.LEFT);
		lblD.setBounds(32, 92, 24, 14);
		contentPane.add(lblD);
		
		comboBoxWritePolicy2 = new JComboBox();
		comboBoxWritePolicy2.setBorder(null);
		comboBoxWritePolicy2.setEnabled(false);
		comboBoxWritePolicy2.setModel(new DefaultComboBoxModel(new String[] {"Writeback - Write alloacte", "Write-through - Write around"}));
		comboBoxWritePolicy2.setBounds(69, 321, 208, 32);
		contentPane.add(comboBoxWritePolicy2);
		
		label = new JLabel("Cache 1");
		label.setBounds(10, 282, 51, 14);
		contentPane.add(label);
		
		lblCache2WritePolicy = new JLabel("Cache 2");
		lblCache2WritePolicy.setBounds(10, 330, 51, 14);
		contentPane.add(lblCache2WritePolicy);
		
		lblCache3WritePolicy = new JLabel("Cache 3");
		lblCache3WritePolicy.setBounds(10, 377, 51, 14);
		contentPane.add(lblCache3WritePolicy);
		
		comboBoxWritePolicy3 = new JComboBox();
		comboBoxWritePolicy3.setEnabled(false);
		comboBoxWritePolicy3.setModel(new DefaultComboBoxModel(new String[] {"Writeback - Write alloacte", "Write-through - Write around"}));
		comboBoxWritePolicy3.setBounds(69, 368, 208, 32);
		contentPane.add(comboBoxWritePolicy3);
		
		lblRequired = new JLabel("* All editable fields are required");
		lblRequired.setForeground(Color.RED);
		lblRequired.setBounds(337, 14, 190, 20);
		contentPane.add(lblRequired);
	}
	public void itemStateChanged(ItemEvent evt) {

        if (evt.getSource()==comboBoxCacheLevels) {
            if(comboBoxCacheLevels.getSelectedIndex()==1)
            {
            	lblCache2.setText("Cache 2");
            	textFieldSCache2.setEnabled(true);
            	textFieldSCache2.setVisible(true);
            	textFieldLCache2.setEnabled(true);
            	textFieldLCache2.setVisible(true);
            	textFieldMCache2.setEnabled(true);
            	textFieldMCache2.setVisible(true);
            	textFieldAccessTimeCache2.setVisible(true);
            	textFieldAccessTimeCache2.setEnabled(true);
            	comboBoxWritePolicy2.setEnabled(true);
            	lblCache3.setText(" ");
            	textFieldSCache3.setEnabled(false);
            	textFieldSCache3.setVisible(false);
            	textFieldLCache3.setEnabled(false);
            	textFieldLCache3.setVisible(false);
            	textFieldMCache3.setEnabled(false);
            	textFieldMCache3.setVisible(false);
            	textFieldAccessTimeCache3.setVisible(false);
            	textFieldAccessTimeCache2.setEnabled(false);
            	comboBoxWritePolicy3.setEnabled(false);
            	this.repaint();
            }
            else if(comboBoxCacheLevels.getSelectedIndex()==2) {
            	lblCache2.setText("Cache 2");
            	textFieldSCache2.setEnabled(true);
            	textFieldSCache2.setVisible(true);
            	textFieldLCache2.setEnabled(true);
            	textFieldLCache2.setVisible(true);
            	textFieldMCache2.setEnabled(true);
            	textFieldMCache2.setVisible(true);
            	textFieldAccessTimeCache2.setVisible(true);
            	textFieldAccessTimeCache2.setEnabled(true);
            	comboBoxWritePolicy2.setEnabled(true);
            	lblCache3.setText("Cache 3");
            	textFieldSCache3.setEnabled(true);
            	textFieldSCache3.setVisible(true);
            	textFieldLCache3.setEnabled(true);
            	textFieldLCache3.setVisible(true);
            	textFieldMCache3.setEnabled(true);
            	textFieldMCache3.setVisible(true);
            	textFieldAccessTimeCache3.setVisible(true);
            	textFieldAccessTimeCache3.setEnabled(true);
            	comboBoxWritePolicy3.setEnabled(true);
            	this.repaint();
            }
            else if(comboBoxCacheLevels.getSelectedIndex()==0)
            {
            	lblCache2.setText(" ");
            	textFieldSCache2.setEnabled(false);
            	textFieldSCache2.setVisible(false);
            	textFieldLCache2.setEnabled(false);
            	textFieldLCache2.setVisible(false);
            	textFieldMCache2.setEnabled(false);
            	textFieldMCache2.setVisible(false);
            	textFieldAccessTimeCache2.setVisible(false);
            	textFieldAccessTimeCache2.setEnabled(false);
            	comboBoxWritePolicy2.setEnabled(false);
            	lblCache3.setText(" ");
            	textFieldSCache3.setEnabled(false);
            	textFieldSCache3.setVisible(false);
            	textFieldLCache3.setEnabled(false);
            	textFieldLCache3.setVisible(false);
            	textFieldMCache3.setEnabled(false);
            	textFieldMCache3.setVisible(false);
            	textFieldAccessTimeCache3.setVisible(false);
            	textFieldAccessTimeCache3.setEnabled(false);
            	comboBoxWritePolicy3.setEnabled(false);
            	this.repaint();
            }
        } 
    }
	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource()==btnNext)
		{
			if(checkFields())
			{
				//assigning the values
				Cache[] caches = new Cache[cachesList.size()];
				for (int i = 0; i < caches.length; i++) {
					caches[i]=cachesList.get(i);
				}
				//Simulator.setCaches(caches);
				simulator.caches = caches; 
				simulator.memoryCapacity = Integer.parseInt(capacityList[comboBoxMemoryCapacity.getSelectedIndex()]);
				simulator.memoryAccessTime = memoryAccessTime;
				//Simulator.setMemoryAccessTime(memoryAccessTime);
				//Simulator.setMemoryCapacity(Integer.parseInt(capacityList[comboBoxMemoryCapacity.getSelectedIndex()]));
				System.out.println("c l s "+cachesList.size());
				System.out.println("s cl "+simulator.cacheLevels);
				System.out.println("s c l"+simulator.caches.length);
				this.dispose();
				
				// opening the next window
				HardwareOrganization hw = new HardwareOrganization(capacityList[comboBoxMemoryCapacity.getSelectedIndex()],this);
			}
			else
			{
				lblError.setVisible(true);
			}
		}
	}
	
	private boolean checkFields() {
		try
		{
			int numberofCaches = comboBoxCacheLevels.getSelectedIndex()+1;
			//simulator.setCacheLevels(numberofCaches);
			//Simulator.setCacheLevels(numberofCaches);
			int writepolicy1 = comboBoxWritePolicy.getSelectedIndex();
			
			Cache iC1;
			Cache dC1;
			
			switch (numberofCaches) {
			case 1:
				int lCache1 = Integer.parseInt(textFieldLCache1.getText());
				int sICache1 = Integer.parseInt(textFieldSICache1.getText());
				int sDCache1 = Integer.parseInt(textFieldSDCache1.getText());
				int mCache1 = Integer.parseInt(textFieldMCache1.getText());
				int AccessTimeCache1 = Integer.parseInt(textFieldAccessTimeCache1.getText());
				
				iC1 = new Cache(sICache1, lCache1, mCache1, AccessTimeCache1, writepolicy1);
				dC1 = new Cache(sDCache1, lCache1, mCache1, AccessTimeCache1, writepolicy1);
				if(sDCache1<sICache1)
					return false;
				cachesList.add(iC1);
				cachesList.add(dC1);
				
				break;
			case 2:
				lCache1 = Integer.parseInt(textFieldLCache1.getText());
				sICache1 = Integer.parseInt(textFieldSICache1.getText());
				sDCache1 = Integer.parseInt(textFieldSDCache1.getText());
				mCache1 = Integer.parseInt(textFieldMCache1.getText());
				AccessTimeCache1 = Integer.parseInt(textFieldAccessTimeCache1.getText());
				
				int writepolicy2 = comboBoxWritePolicy2.getSelectedIndex();
				
				int lCache2 = Integer.parseInt(textFieldLCache2.getText());
				int sCache2 = Integer.parseInt(textFieldSCache2.getText());
				int mCache2 = Integer.parseInt(textFieldMCache2.getText());
				int AccessTimeCache2 = Integer.parseInt(textFieldAccessTimeCache2.getText());
				
				if(sICache1>sCache2||lCache1>lCache2||mCache2>sCache2/lCache2||mCache1>sICache1/lCache1||AccessTimeCache1>AccessTimeCache2||AccessTimeCache1<0)
					return false;
				iC1 = new Cache(sICache1, lCache1, mCache1, AccessTimeCache1, writepolicy1);
				dC1 = new Cache(sDCache1, lCache1, mCache1, AccessTimeCache1, writepolicy1);
				Cache c2 =  new Cache(sCache2, lCache2, mCache2, AccessTimeCache2, writepolicy2);
				cachesList.add(iC1);
				cachesList.add(dC1);
				cachesList.add(c2);
				break;
			case 3:
				lCache1 = Integer.parseInt(textFieldLCache1.getText());
				sICache1 = Integer.parseInt(textFieldSICache1.getText());
				sDCache1 = Integer.parseInt(textFieldSDCache1.getText());
				mCache1 = Integer.parseInt(textFieldMCache1.getText());
				AccessTimeCache1 = Integer.parseInt(textFieldAccessTimeCache1.getText());
				
				
				lCache2 = Integer.parseInt(textFieldLCache2.getText());
				sCache2 = Integer.parseInt(textFieldSCache2.getText());
				mCache2 = Integer.parseInt(textFieldMCache2.getText());
				AccessTimeCache2 = Integer.parseInt(textFieldAccessTimeCache2.getText());
				writepolicy2 = comboBoxWritePolicy2.getSelectedIndex();
				
				int lCache3 = Integer.parseInt(textFieldLCache3.getText());
				int sCache3 = Integer.parseInt(textFieldSCache3.getText());
				int mCache3 = Integer.parseInt(textFieldMCache3.getText());
				int AccessTimeCache3 = Integer.parseInt(textFieldAccessTimeCache3.getText());
				int writepolicy3 = comboBoxWritePolicy3.getSelectedIndex();
				
				if(sICache1>sCache2||sICache1>sCache3||sCache2>sCache3||lCache1>lCache2||lCache1>lCache3||lCache2>lCache3||sICache1<=0||AccessTimeCache1>AccessTimeCache2||AccessTimeCache2>AccessTimeCache3||AccessTimeCache1<0||mCache3>sCache3/lCache3||mCache2>sCache2/lCache2||mCache1>sICache1/lCache1)
					return false;
				iC1 = new Cache(sICache1, lCache1, mCache1, AccessTimeCache1, writepolicy1);
				dC1 = new Cache(sDCache1, lCache1, mCache1, AccessTimeCache1, writepolicy1);
				c2 = new Cache(sCache2, lCache2, mCache2, AccessTimeCache2, writepolicy2);
				Cache c3 = new Cache(sCache3, lCache3, mCache3, AccessTimeCache3, writepolicy3);
				cachesList.add(iC1);
				cachesList.add(dC1);
				cachesList.add(c2);
				cachesList.add(c3);
				break;
			default:
				break;
			}
			memoryAccessTime = Integer.parseInt(textFieldMemoryAccessTime.getText());
			simulator.cacheLevels = numberofCaches;
		}
		catch (NumberFormatException e) {
			
			return false;
		}
		
		return true;
	}

	private class SwingAction extends AbstractAction {
		public SwingAction() {
			putValue(NAME, "Next");
			putValue(SHORT_DESCRIPTION, "Some short description");
		}
		public void actionPerformed(ActionEvent e) {
			
		}
	}
}
